import WebGl from '@/modules/three';
// import fontJson from 'three/examples/fonts/helvetiker_regular.typeface.json'
const fontJson = require('three/examples/fonts/helvetiker_regular.typeface.json');

const { Three, TWEEN, dat } = WebGl;

class WebGlControl {
  private container: any;
  private camera: any;
  private scene: any;
  private renderer: any;
  private animateFrame: any;
  private starsGroup: any; //
  private pointsGroup: any; //

  private Geometrys: {
    cubeGeometry?: any;
    starsGeometry?: any;
    pointsGeometry?: any;
  } = {}; //保存所有Geometry，方便统一销毁
  private Materials: {
    cubeMaterial?: any;
    starsMaterial?: any;
    pointsMaterial?: any;
  } = {}; //保存所有Material，方便统一销毁

  private GuiInit: any = null;
  private guiData: any = {
    x: 0.005,
    color: '#fafafa',
    autoRotate: false,
  };
  private mouseData: any = {
    mouseX: 0,
    mouseY: 0,
  };

  public init = () => {
    // if(this.scene) {return}
    this.container = document.getElementById('WebGL-points-test');
    let width = this.container.clientWidth,
      height = this.container.clientHeight;

    this.scene = new Three.Scene();

    this.camera = new Three.PerspectiveCamera(60, width / height, 1, 2000);
    this.camera.position.x = 0;
    this.camera.position.y = 20;
    this.camera.position.z = 500;
    this.camera.lookAt(this.scene.position);

    this.renderer = new Three.WebGLRenderer();
    // this.renderer.setClearColor( 0xffffff );
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width, height);
    this.container.appendChild(this.renderer.domElement);

    this.addThings();
    this.addLight(); //+光源
    this.animate(); //开始动
    this.initEventListen();

    this.initGui();
  };
  public destroy = () => {
    this.toggleGui(0);
    Object.values(this.Geometrys).forEach((e) => {
      e.dispose();
    });
    Object.values(this.Materials).forEach((e) => {
      e.dispose();
    });
    this.scene.clear();
    this.renderer.dispose();
    this.renderer.forceContextLoss();
    this.camera = null;
    this.scene = null;
    this.renderer = null;
    this.GuiInit = null;
    cancelAnimationFrame(this.animateFrame);
  };

  public initGui = () => {
    if (this.GuiInit) {
      this.toggleGui();
      return;
    }
    this.GuiInit = new dat.GUI({
      // autoPlace: false
    });

    this.GuiInit.domElement.style.position = 'absolute';
    this.GuiInit.domElement.style.right = '10px';
    this.GuiInit.domElement.style.top = '10px';

    let GuiController = this.GuiInit.addFolder('控制窗口');
    GuiController.add(this.guiData, 'x', -0.1, 0.1, 0.005).name('自转速度');
    GuiController.addColor(this.guiData, 'color').name('背景颜色');
    GuiController.open();

    let starsGui = this.GuiInit.addFolder('stars position');
    starsGui.add(this.starsGroup.position, 'x', -500, 500, 1);
    starsGui.add(this.starsGroup.position, 'y', -500, 500, 1);
    starsGui.add(this.starsGroup.position, 'z', -500, 500, 1);
    starsGui.open();

    let starsGuiRotate = this.GuiInit.addFolder('stars rotation');
    starsGuiRotate.add(this.guiData, 'autoRotate').name('自动旋转');
    starsGuiRotate.add(this.starsGroup.rotation, 'x', -3.14, 3.14, 0.01);
    starsGuiRotate.add(this.starsGroup.rotation, 'y', -3.14, 3.14, 0.01);
    starsGuiRotate.add(this.starsGroup.rotation, 'z', -3.14, 3.14, 0.01);
    //rotation是欧拉类型的值，单位是π；比如让物体按Y轴正方向旋转45°可以写成 object3D.rotation.y+=0.25*Math.PI
    starsGuiRotate.open();
  };

  public toggleGui = (state: any = null) => {
    if (!this.GuiInit || !this.GuiInit.domElement) {
      return;
    }
    let display = this.GuiInit.domElement.style.display == 'none' ? '' : 'none';
    if (state == 0) {
      display = 'none';
    }
    this.GuiInit.domElement.style.display = display;
  };

  private initEventListen = () => {
    this.container.addEventListener('pointermove', this.onPointerMove);
  };
  private onPointerMove = (event) => {
    if (event.isPrimary === false) return;
    this.mouseData.mouseX = event.clientX - this.container.clientWidth;
    this.mouseData.mouseY = event.clientY - this.container.clientHeight;
  };

  private addLight = () => {
    // let ambi = new Three.AmbientLight(0x686868);
    // this.scene.add(ambi);
    // let spotLight = new Three.DirectionalLight(0xffffff);
    // spotLight.position.set(550, 100, 550);
    // spotLight.intensity = 0.6;
    // this.scene.add(spotLight);
    // let light = new Three.PointLight( 0xFFFF00 );
    // light.position.set( -100, 100, 0 );
    // this.scene.add(light);
  };

  private addThings = () => {
    const axesHelper = new Three.AxesHelper(800);
    this.scene.add(axesHelper); //添加坐标轴；红线是X轴，绿线是Y轴，蓝线是Z轴

    /** 立方体 **/
    // this.Geometrys.cubeGeometry = new Three.BoxGeometry( 100, 100, 100);
    // this.Materials.cubeMaterial = new Three.MeshLambertMaterial( { color: 0xfd59d7 } );
    // const cube = new Three.Mesh( this.Geometrys.cubeGeometry, this.Materials.cubeMaterial );
    // this.scene.add( cube );
    /** 立方体 **/

    /** 星空 **/
    this.starsGroup = new Three.Group();
    this.scene.add(this.starsGroup);
    this.Geometrys.starsGeometry = new Three.BufferGeometry();
    let starArr: any[] = [];
    for (let i = 0; i < 1000; i++) {
      const x = Three.MathUtils.randFloatSpread(150);
      const y = Three.MathUtils.randFloatSpread(150);
      const z = Three.MathUtils.randFloatSpread(150);
      starArr.push(x, y, z);
    }
    this.Geometrys.starsGeometry.setAttribute(
      'position',
      new Three.Float32BufferAttribute(starArr, 3),
    );
    this.Materials.starsMaterial = new Three.PointsMaterial({
      color: 0xfd59d7,
      size: 1,
    });
    const stars = new Three.Points(
      this.Geometrys.starsGeometry,
      this.Materials.starsMaterial,
    );
    this.starsGroup.add(stars);
    /** 星空 **/

    /** 球面粒子 **/
    let sphereGeometry = new Three.SphereGeometry(90, 58, 28); //新建一个球体
    sphereGeometry.deleteAttribute('normal');
    sphereGeometry.deleteAttribute('uv');
    let spherePosition = sphereGeometry.getAttribute('position');

    this.pointsGroup = new Three.Group();
    this.scene.add(this.pointsGroup);
    this.Geometrys.pointsGeometry = new Three.BufferGeometry();
    let positions: any[] = [];
    let sizes: any[] = [];
    let colors: any[] = [];
    const color = new Three.Color();

    for (let i = 0; i < spherePosition.count; i++) {
      // const x = Three.MathUtils.randFloatSpread( 150 );
      // const y = Three.MathUtils.randFloatSpread( 150 );
      // const z = Three.MathUtils.randFloatSpread( 150 );
      // positions.push(x,y,z)
      sizes.push(Math.random() * 15);
      color.setHSL(0.01 + 0.1 * (i / 400), 0.99, 0.25 + 0.1 * (i / 400));
      colors = [...colors, ...color.toArray()];
    }

    // this.Geometrys.pointsGeometry.setAttribute('position', new Three.Float32BufferAttribute(positions, 3))
    this.Geometrys.pointsGeometry.setAttribute(
      'position',
      new Three.Float32BufferAttribute(spherePosition.array, 3),
    ); //直接用球面体的position
    this.Geometrys.pointsGeometry.setAttribute(
      'size',
      new Three.Float32BufferAttribute(sizes, 1),
    );
    this.Geometrys.pointsGeometry.setAttribute(
      'ca',
      new Three.Float32BufferAttribute(colors, 3),
    );

    const texture = new Three.TextureLoader().load('../../disc.png');
    texture.wrapS = Three.RepeatWrapping;
    texture.wrapT = Three.RepeatWrapping;

    this.Materials.pointsMaterial = new Three.ShaderMaterial({
      uniforms: {
        color: { value: new Three.Color(0xffffff) },
        pointTexture: { value: texture },
      },
      vertexShader: `
        attribute float size;
        attribute vec3 ca;

        varying vec3 vColor;

        void main() {

          vColor = ca;

          vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

          gl_PointSize = size * ( 300.0 / -mvPosition.z );

          gl_Position = projectionMatrix * mvPosition;

        }
      `,
      fragmentShader: `
        uniform vec3 color;
        uniform sampler2D pointTexture;

        varying vec3 vColor;

        void main() {

          vec4 color = vec4( color * vColor, 1.0 ) * texture2D( pointTexture, gl_PointCoord );

          gl_FragColor = color;

        }
      `,
      transparent: true,
    });

    const points = new Three.Points(
      this.Geometrys.pointsGeometry,
      this.Materials.pointsMaterial,
    );
    this.pointsGroup.add(points);
    /** 球面粒子 **/

    console.log(
      'geometry',
      spherePosition,
      this.Geometrys.starsGeometry,
      this.Geometrys.pointsGeometry,
    );
    this.initTween();
  };

  private initTween = () => {
    // cameray: 20, z: 500
    var tween = new TWEEN.Tween(this.starsGroup.position)
      .to({ y: 12, z: 300 }, 1000)
      .start();
    // tween.easing(TWEEN.Easing.Sinusoidal.InOut);
    tween.easing(TWEEN.Easing.Circular.Out);

    var tween1 = new TWEEN.Tween(this.pointsGroup.position)
      .to({ y: 12, z: 300 }, 1000)
      .delay(500);
    tween1.easing(TWEEN.Easing.Circular.Out);
    tween1.start();
  };

  private animate = () => {
    // if(!this.renderer){return;}
    this.animateFrame = requestAnimationFrame(this.animate);
    this.render();
    TWEEN.update();
  };
  private render = () => {
    this.renderer.setClearColor(this.guiData.color, 1.0);
    if (this.guiData.autoRotate) {
      // this.starsGroup.rotation.x+= 0.025
      this.starsGroup.rotation.y += 0.015;
    }

    const time = Date.now() * 0.005;
    this.pointsGroup.rotation.y = this.guiData.x * time;
    this.pointsGroup.rotation.z = this.guiData.x * time;

    /*粒子大小更新*/
    const attributes = this.Geometrys.pointsGeometry.attributes;
    for (let i = 0; i < attributes.size.array.length; i++) {
      attributes.size.array[i] = 10 + 6 * Math.sin(0.1 * i + time);
    }
    attributes.size.needsUpdate = true;
    /*粒子大小更新*/

    // this.camera.position.x += ( this.mouseData.mouseX - this.camera.position.x ) * 0.015;
    // this.camera.position.y += ( - this.mouseData.mouseY - this.camera.position.y ) * 0.015;

    this.renderer.render(this.scene, this.camera);
  };
}

const webGlControl = new WebGlControl();
export default webGlControl;
